<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <link rel="icon" href="*{images/favicon.ico}" type="image/x-icon" />
  <meta http-equiv="P3P" content="CP='NOI NID'">
  <meta http-equiv="_broadcast_from_" Content="1" />
  <script type="text/javascript" src="*{/js/jquery.js}"></script>
  <script type="text/javascript" src="*{/js/func.js}"></script>
  <script type="text/javascript" src="*{/js/base64.js}"></script>
<style>
html,body{
  margin:0;
  padding:0;
}
</style>
	<title>log_JPhenix内部实时日志</title>
<style type="text/css">
html, body { padding:0px; margin:0px; }
.row {
  margin-left:30px;
  margin-top:20px;
  font-size:13px;
}
a{color:bule;font-weight:bold;font-size:14px;text-decoration:none}
a:hover{color:red;}
a:active{color:yellow;}
#sql_history #sql_time {
	text-align:center;
	width:140px;
	margin:0px;
	padding:0px;
}
#sql_history #sql_source {
	text-align:center;
	padding-left:3px;
	padding-right:3px;
}
#sql_history #sql_content {
	padding:3px;
}
#sql_history #sql_deal{
	width:40px;
	text-align:center;
	padding:3px;
}
</style>
</head>
<body>
<div class="main_div" style="background-color:#000000;">
	<div id="top_area" style="style:width:100%;height:28px;padding-left:15px;font-size:10px;position:absolute;left:0px;top:0px;background-color:#FFFFFF;border:solid 1px #FFFFFF;">
      <div style="float:left;padding-top:5px;">
        [ <span title="科呜恩g控，只日制。来，乖，跟着一起读">控制:</span>
      <input type="checkbox" id="bt_run" checked onclick="javascript:doWork(this.checked);"/><label title="取消勾选则停止接收新的日志" for="bt_run">运行</label>
	    <input type="checkbox" id="bt_push" checked onclick="javascript:doRefresh(this);"/><label title="取消勾选后，新增加日志时并不会将滚动条移动到最底端，便于查看上面的日志，勾选后便于查看最新日志" for="bt_push">滚屏</label>
      <input type="checkbox" id="bt_cluster" onclick="javascript:doCluster(this.checked);"/><label title="是否接受当前群组中所有服务器日志" for="bt_cluster">集群</label>
      <input type="button" value="清屏" onclick="logArea.empty();" title="按住Shift键然后双击日志区域也可以清空日志"/>
      ]
	</div>
	 <div style="margin-left:10px;height:23px;background-color:#000000;float:left;color:white;padding-left:10px;padding-right:10px;padding-top:5px;">
	  [<span title="不勾选，则不输出该类型的日志，并删除已经显示的该类型的日志" onclick="javascript:checkAll(this);">输出:</span>
        <input type="checkbox" checked log_type="log" id="ck_log" onclick="javascript:outLog=this.checked;emptyElement(this);"/><label for="ck_log" style="color:#FFFFFF;" ondblclick="javascript:checkOne('log',this);" title="开发时最常用的调试日志，量最大，最细">日志</label>
        <input type="checkbox" checked log_type="wrn" id="ck_wrn" onclick="javascript:outWrn=this.checked;emptyElement(this);"/><label for="ck_wrn" style="color:#FFFF00;" ondblclick="javascript:checkOne('wrn',this);" title="出现错误，但不影响继续运行的日志">警告</label>
        <input type="checkbox" checked log_type="err" id="ck_err" onclick="javascript:outErr=this.checked;emptyElement(this);"/><label for="ck_err" style="color:#FF0000;" ondblclick="javascript:checkOne('err',this);" title="发生了不该发生的错误，需要解决的错误">错误</label>
       <input type="checkbox"  checked log_type="deb" id="ck_deb" onclick="javascript:outDeb=this.checked;emptyElement(this);"/><label for="ck_deb" style="color:#CC9933;" ondblclick="javascript:checkOne('deb',this);" title="这个日志通常不写入日志文件，只做动态实时输出，日志内容更加详细。配置文件中有个开关可以将这类日志写入文件，但不建议这么做，会导致日志数据巨大">调试</label>
       <input type="checkbox"  checked log_type="ifo" id="ck_ifo" onclick="javascript:outIfo=this.checked;emptyElement(this);"/><label for="ck_ifo" style="color:#FF9900;" ondblclick="javascript:checkOne('ifo',this);" title="区别于调试日志，通常用来显示普通信息，便于调试">信息</label>
        <input type="checkbox" checked log_type="sql" id="ck_sql" onclick="javascript:outSql=this.checked;emptyElement(this);"/><label for="ck_sql" style="color:#CCFF33;" ondblclick="javascript:checkOne('sql',this);" title="操作数据库相关的日志，通常该类日志都是由框架输出的，无需人为编写">语句</label>
        <input type="checkbox" checked log_type="dat" id="ck_dat" onclick="javascript:outDat=this.checked;emptyElement(this);"/><label for="ck_dat" style="color:#FFCCFF;" ondblclick="javascript:checkOne('dat',this);" title="调用接口发送返回报文等数据，这类数据量也很大，通常在排错时不一定看这类日志。这类日志存放在另外一个专用的日志文件中，每天生成一个备份包">数据</label>
        <input type="checkbox" checked log_type="rut" id="ck_rut" onclick="javascript:outRut=this.checked;emptyElement(this);"/><label for="ck_rut" style="color:#778899;" ondblclick="javascript:checkOne('rut',this);" title="用来显示某一段执行耗费时间，用来做程序性能调优">性能</label>
        <input type="checkbox" checked log_type="tmp" id="ck_rut" onclick="javascript:outRut=this.checked;emptyElement(this);"/><label for="ck_tmp" style="color:#73ffff;" ondblclick="javascript:checkOne('tmp',this);" title="用来做当前调试，调试后需要删除该日志输出">临时</label>
        <input type="checkbox" checked log_type="unk" id="ck_unk" onclick="javascript:outUnk=this.checked;emptyElement(this);"/><label for="ck_unk" style="color:#33CCCC;" ondblclick="javascript:checkOne('unk',this);" title="后台输出的，页面中无法正常分类显示的日志">未知</label>

      ]
     </div>
     <div style="margin-left:10px;float:left;padding-left:10px;padding-right:10px;padding-top:5px;background-color:#FFFFFF;">
       [ 过滤：
       	<span title="多个线程号用半角逗号分割">线程号：</span><input type="text" style="width:40px;" id="thread_filter"/>
        <span title="多个关键字用半角逗号分割">关键字：</span><input type="text" style="width:40px;" id="keyword_filter"/>
        <span title="可以只显示指定会话日志">会话：</span><input type="text" style="width:40px;" id="session_filter"/>
        <span title="请求端IP地址">IP：</span><input type="text" style="width:40px;" id="ip_filter"/>
        <input type="radio" name="filter_type" checked id="filter_radio_imp" onclick="javascript:isImpOut=true;"/><span title="凡是符合条件的凑显示">包含</span>
       <input type="radio" name="filter_type" id="filter_radio_exp" onclick="javascript:isImpOut=false;"/><span title="凡是符合条件的都排除">排除</span>
       <input type="button" value="重置" onclick="javascript:resetFilter();" />
       ]
     </div>
      <div style="float:left;padding-top:5px;background-color:#FFFFFF;">
        <div style="float:left;margin-top:5px;">[ <span title="间隔闪烁代表与后台实时沟通，获取最新的数据">状态：</span></div>
        <div style="float:left;width:12px;height:12px;border-radius:60px;background-color:#FFFFFF;margin-right:10px;margin-top:6px;" id="net_status"></div>
        <div style="float:left;width:12px;height:12px;border-radius:60px;background-color:#FFFFFF;margin-right:10px;margin-top:6px;" id="net_status_cluster"></div>
         <div style="float:left;margin-top:5px;">]</div>
      </div>
    </div>
    <div id="log_area" ondblclick="javascript:clickEmptyLog(event);" style="padding-left:5px;padding-right:0px;margin-top:30px;border:solid 1px #EFEFEF;background-color:#000000;overflow:auto;"></div>
</div>
<script type="text/javascript">
var ts;
var oTsMap = new ValueMap();
var token;
var INTERVAL_TIME = 200;
var orderRun = true;
var orderRefresh = true;
var logArea = $("#log_area");
var topArea = $("#top_area");
var netStatus = $("#net_status");
var netStatusCluster = $("#net_status_cluster");
var isNetStatusOn = false;
var isNetStatusOnCluster = false;

var tfInput = $("#thread_filter");
var kwInput = $("#keyword_filter");
var seInput = $("#session_filter");
var ipInput = $("#ip_filter");

var doOutCluster = false;
var isImpOut     = true;
var outLog       = true;
var outWrn       = true;
var outErr       = true;
var outRut       = true;
var outDat       = true;
var outSql       = true;
var outUnk       = true;
var outDeb       = true;
var outIfo       = true;
var outTmp       = true;

window.onload=function(){  
  window.onresize = adjust;  
  adjust();
  doWork(true);
}

function doRefresh(node){
  if(node.checked){
    orderRefresh = true;
  }else{
    orderRefresh = false;
  }
}

function doCluster(enabled){
  doOutCluster = enabled;
  if(enabled){
    oTsMap = new ValueMap();
    loadClusterData();
  }
}

function doWork(enabled){
  orderRun = enabled;
  if(enabled){
    getToken();
    ts = "";
    loadData();
    
    doCluster($("#bt_cluster")[0].checked);
  }
}

function getToken(){
  var res = getUrlValue("*{/N100033.ha}&token="+(token?token:""));
  if(!res){
    return;
  }
  try{
    	eval("res = "+res);
  }catch(e){}
  if(!res || !res.token){
    console.log("错误，没有获取到token");
    addLog("","","[err]","","","","","","","没有获取到token");
    return;
  }
  token = res.token;
}

function loadClusterData(){
  flashNetStatusCluster();
  var source = "";
  var tsStr = "";
  var keys = oTsMap.getKeys();
  if(keys && keys.length>0){
    for(var i=0;i<keys.length;i++){
      tsStr += "&_"+keys[i]+"="+oTsMap.get(keys[i]);
    }
  }
  try{
    source = getUrlValue("*{}/_log.ha?_o=1&token="+token+tsStr);
    eval(source);
  }catch(e){
    addLog("","","[err]","","","","","","","读取集群日志发生错误，读取终止:["+source+"]");
    console.log(source);
    return;
  }
  if(orderRun && doOutCluster){
    window.setTimeout(loadClusterData,INTERVAL_TIME);
  }
}

function loadData(){
  flashNetStatus();
  var source = "";
  try{
    source = getUrlValue("*{}/_log.ha?token="+token+"&ts="+ts);
    eval(source);
  }catch(e){
      addLog("","","[err]","","","","","","","读取日志发生错误，读取终止:["+source+"]");
      console.log(source);
      return;
  }
  if(!source || source==""){
    addLog("","","[err]","","","","","","","读取日志中断");
    return;
  }
  if(orderRun){
    window.setTimeout(loadData,INTERVAL_TIME);
  }
}

function fixLogData(json){
  if(!json){
    return;
  }
  var serverName;
  if(json.server){
    serverName = json.server;
  }
  if(json.local=="1"){
    ts = json._ts;
  }else{
    oTsMap.put(serverName,json._ts);
  }
  var groupName;
  if(json.group){
    groupName = json.group;
  }
  if(json.element.length>0){
    var eles = json.element;
    var ele;
    for(var i=0;i<eles.length;i++){
      ele = Base64.decode(eles[i]);
      parseLog(ele,groupName,serverName);
    }
  }
}

function emptyElement(node){
  if(node.checked){
    return;
  }
  node = $(node);
  logArea.find("[atype='"+node.attr("log_type")+"']").empty();
}

function checkAll(node){
  node = $(node);
  if(node.attr("svalue")=="1"){
    node.attr("svalue","0");
    node.parent().find("[type='checkbox']").each(function(i){this.checked=false;this.onclick();});
  }else{
    node.attr("svalue","1");
    node.parent().find("[type='checkbox']").each(function(i){this.checked=true;this.onclick();});
  }
}

function checkOne(key,node){
  node = $(node);
  node.parent().find("[type='checkbox']").each(function(i){
    if(this.getAttribute("log_type")==key){
      this.checked = true;
    }else{
      this.checked = false;
    }
    this.onclick();
  });
}

function resetFilter(){
  tfInput.val("");
  kwInput.val("");
  seInput.val("");
  ipInput.val("");
  $("#filter_radio_imp")[0].checked = true;
  $("#filter_radio_exp")[0].checked = false;
  isImpOut = true;
}

function clickEmptyLog(evt){
	if(!evt.shiftKey && !evt.ctrlKey && !evt.altKey){
		return;
	}
	logArea.empty();
}

function flashNetStatusCluster(){
  if(isNetStatusOnCluster){
    netStatusCluster.css("background-color","#FFFFFF");
    isNetStatusOnCluster = false;
  }else{
    netStatusCluster.css("background-color","#0080ff");
    isNetStatusOnCluster = true;
  }
}

function flashNetStatus(){
  if(isNetStatusOn){
    netStatus.css("background-color","#FFFFFF");
    isNetStatusOn = false;
  }else{
    netStatus.css("background-color","#00ff00");
    isNetStatusOn = true;
  }
}

function adjust(obj){  
  var logArea = $("#log_area");
	logArea.css("height",$(document).height()-50);
  logArea.css("width",$(document).width()-4);
}  


function parseLog(log,groupName,serverName){
  if(!log || log.length<38){
    return;
  }
  var point = log.indexOf("\n");
  if(point==0){
    log = log.substring(1,log.length);
    point = log.indexOf("\n");
  }
  var headInfo = log.substring(0,point);
  log = log.substring(point,log.length);
  var type = headInfo.substring(0,5);
  headInfo = headInfo.substring(6,headInfo.length);
  var time = "";
  point = headInfo.indexOf("t:[");
  if(point>-1){
    headInfo = headInfo.substring(point+3,headInfo.length);
    point = headInfo.indexOf("]");
    if(point>0){
      time = headInfo.substring(0,point);
      headInfo.substring(point+1,headInfo.length);
      
      point = time.indexOf(" "); //去掉日期
      if(point>0){
        time = time.substring(point+1,time.length);
      }
    }
  }
  var bossName = "";
  point = headInfo.indexOf("b:[");
  if(point>-1){
    headInfo = headInfo.substring(point+3,headInfo.length);
    point = headInfo.indexOf("]");
    if(point>0){
      bossName = headInfo.substring(0,point);
      headInfo.substring(point+1,headInfo.length);
    }
  }
  var threadNo = "";
  point = headInfo.indexOf("h:[");
  if(point>-1){
    headInfo = headInfo.substring(point+3,headInfo.length);
    point = headInfo.indexOf("]");
    if(point>0){
      threadNo = headInfo.substring(0,point);
      headInfo.substring(point+1,headInfo.length);
    }
  }
  
  var sessionId = "";
  point = headInfo.indexOf("s:[");
  if(point>-1){
    headInfo = headInfo.substring(point+3,headInfo.length);
    point = headInfo.indexOf("]");
    if(point>0){
      sessionId = headInfo.substring(0,point);
      headInfo.substring(point+1,headInfo.length);
    }
  }
  
  var ip = "";
  point = headInfo.indexOf("p:[");
  if(point>-1){
    headInfo = headInfo.substring(point+3,headInfo.length);
    point = headInfo.indexOf("]");
    if(point>0){
      ip = headInfo.substring(0,point);
      headInfo.substring(point+1,headInfo.length);
    }
  }
  
  var action = "";
  point = headInfo.indexOf("a:[");
  if(point>-1){
    headInfo = headInfo.substring(point+3,headInfo.length);
    point = headInfo.indexOf("]");
    if(point>0){
      action = headInfo.substring(0,point);
      headInfo.substring(point+1,headInfo.length);
    }
  }
  
  var ms = "";
  point = headInfo.indexOf("ms:[");
  if(point>-1){
    headInfo = headInfo.substring(point+4,headInfo.length);
    point = headInfo.indexOf("]");
    if(point>0){
      ms = headInfo.substring(0,point);
      headInfo.substring(point+1,headInfo.length);
    }
  }
  addLog(groupName,serverName,type,time,threadNo,sessionId,ip,action,bossName,ms,log);
}


function addLog(groupName,serverName,type,ts,threadNo,sessionId,ip,action,invoker,ms,content){
  if(!content){
    return;
  }
  var isOut;
  if(tfInput.val() && threadNo){
    var tfs = tfInput.val().split(",");
    if(isImpOut){
      isOut = false;
    }else{
      isOut = true;
    }
	  for(var i=0;i<tfs.length;i++){
	  	if(tfs[i]==threadNo){
	  		isOut = true;
	  		break;
	  	}
	  }
	  if(!isOut){
	  	return;
	  }
  }
  if(kwInput.val()!=""){
    var kws = kwInput.val().split(",");
    if(isImpOut){
      isOut = false;
    }else{
      isOut = true;
    }
	  for(var i=0;i<kws.length;i++){
	  	if(content.indexOf(kws[i])>-1){
	  		isOut = !isOut;
	  		break;
	  	}
	  }
	  if(!isOut){
	  	return;
	  }
  }
  if(seInput.val()!="" && seInput.val()!=sessionId){
    return;
  }
  
  if(ipInput.val()!="" && ipInput.val()!=ip){
    return;
  }
  
  var color = "#FFFFFF";
  var typeStr;
  var typeKey;
  if(type=="[log]"){
    if(!outLog){
      return;
    }
    typeKey = "log";
    color = "#EEEEEE";
    typeStr = "日志";
  }else if(type=="[wrn]"){
    if(!outWrn){
      return;
    }
    typeKey = "wrn";
    color = "#FFFF00";
    typeStr = "警告";
  }else if(type=="[err]"){
    if(!outErr){
      return;
    }
    typeKey = "err";
    color = "#FF0000";
    typeStr = "错误";
  }else if(type=="[deb]"){
    if(!outDeb){
      return;
    }
    typeKey = "deb";
    color = "#CC9933";
    typeStr = "调试";
  }else if(type=="[ifo]"){
    if(!outIfo){
      return;
    }
    typeKey = "ifo";
    color = "#FF9900";
    typeStr = "信息";
  }else if(type=="[rut]"){
    if(!outRut){
      return;
    }
    typeKey = "rut";
    color = "#778899";
    typeStr = "性能";
  }else if(type=="[sql]"){
    if(!outSql){
      return;
    }
    typeKey = "sql";
    color = "#CCFF33";
    typeStr = "语句";
  }else if(type=="[dat]"){
    if(!outDat){
      return;
    }
    typeKey = "dat";
    color = "#FFCCFF";
    typeStr = "数据";
  }else if(type=="[unk]"){
    if(!outUnk){
      return outUnk;
    }
    typeKey = "unk";
    color = "#33CCCC";
    typeStr = "未知";
  }else if(type=="[tmp]"){
    typeKey = "tmp";
    color = "#73ffff";
    typeStr = "临时";
  }else{
    if(!outUnk){
      return;
    }
    typeKey = "unk";
    color = "#EEEEEE";
    typeStr = "日志";
  }
  if(content.substring(0,1)=="\n"){
    content = content.substring(1,content.length);
  }
  var msInfo = "";
  if(ms){
    msInfo = "&nbsp;耗费时间:<span style=\"color:#D3D3D3;\">["+ms+"]</span>";
  }
  var clusterInfo = ""; //集群信息
  if(groupName && groupName!=""){
    clusterInfo = "&nbsp;&nbsp;分组：<span style=\"color:#ffffbf;\">"+groupName+"</span>";
  }
  if(serverName && serverName!=""){
    clusterInfo += "&nbsp;&nbsp;主机：<span style=\"color:#ffffbf;\">"+serverName+"</span>";
  }
  content = 
    content
  		.replace(/\&/g,"&amp;")
  		.replace(/\</g,"&lt;")
  		.replace(/\>/g,"&gt;")
    	.replace(/\n/g,"<br />")
    	.replace(/\*\*\*c:\[/g,"")
    	.replace(/\]\*\*\*/g,"")
    	.replace(/\[\]/g,"");
  if(typeKey=="unk"){
    logArea.append("<div atype=\""+typeKey+"\" style=\"font-size:10px;margin-top:3px;width:100%;color:#808080;\">"+clusterInfo+"&nbsp;&nbsp;<span style=\"color:red;\">"+content+"</span></div>");
  }else{
    logArea.append("<div atype=\""+typeKey+"\"><div style=\"font-size:10px;margin-top:3px;width:100%;color:#808080;\">类型：<span style=\"color:"+color+";\">"+typeStr+"</span>"+clusterInfo+"&nbsp;&nbsp;时间：<span style=\"color:#228B22;\">"+ts+"</span>&nbsp;线程：<span style=\"color:#D3D3D3;\">"+threadNo+"</span>&nbsp;会话：<span style=\"color:#D3D3D3;\">"+sessionId+"</span>&nbsp;源IP：<span style=\"color:#D3D3D3;\">"+ip+"</span>&nbsp;动作：<span style=\"color:#D3D3D3;\">"+action+"</span>&nbsp;调用者：<span style=\"color:#D3D3D3;\">"+invoker+"</span>"+msInfo+"</div><div style=\"margin-top:3px;font-size:12px;border-bottom:solid 1px #5E5E5E;width:"+($(document).width()-30)+"px;color:"+color+";padding-bottom:3px;\">"+content+"</div></div>");
  }
  if(orderRefresh){
    logArea.scrollTop(logArea[0].scrollHeight);
  }
}

</script>
</body>
</html>